package com.hmall.gateway.routers;

import cn.hutool.json.JSONUtil;
import com.alibaba.cloud.nacos.NacosConfigManager;
import com.alibaba.nacos.api.config.listener.Listener;
import com.alibaba.nacos.api.exception.NacosException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.bouncycastle.asn1.dvcs.DVCSObjectIdentifiers;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.route.RouteDefinitionWriter;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;

import javax.annotation.PostConstruct;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.Executor;

@Slf4j
@Component
@RequiredArgsConstructor
public class DynamicRouteLoader {

    private final NacosConfigManager nacosConfigManager;
     private final RouteDefinitionWriter writer;

    private final String dataId = "gateway-routes.json";

    private final String group = "DEFAULT_GROUP";

     private final Set<String> routeIds = new HashSet<>();

    @PostConstruct//配合Component可以使项目已启动就执行这个方法
    public void initRouteConfigListener() throws NacosException {  //初始化路由
         // 1.项目启动时，先拉去一次配置，并配置监听器
          String configInfo = nacosConfigManager.getConfigService()
                .getConfigAndSignListener(dataId, group, 5000, new Listener() {
                    @Override
                    public Executor getExecutor() {

                        return null;

                    }
                    @Override
                    public void receiveConfigInfo(String configInfo) {
                      // 2.监听到配置变更，更新路由表
                        updateConfigInfo(configInfo);
                    }
                });

          //3.第一次读取到配置。也需要更新到路由表
          updateConfigInfo(configInfo);
    }



    public void updateConfigInfo(String configInfo){
       log.debug("监听到路由配置信息: {}",configInfo);

            //  1.解析配置信息，转换为RouteDefinition TODO
            List<RouteDefinition> routeDefinitions = JSONUtil.toList(configInfo ,RouteDefinition.class);

            //2.删除旧的路由表
         for(String routId: routeIds){
            writer.delete(Mono.just(routId)).subscribe();
          }
        routeIds.clear();

        //3.更新路由表
            for(RouteDefinition routeDefinition : routeDefinitions){
             //3.1 更新路由表
                writer.save(Mono.just(routeDefinition)).subscribe();
               //3.2记录路由id，便于下一次更新时删除

                routeIds.add(routeDefinition.getId());

            }
    }
}
